<template>
    <h2>Reflect对象的13个静态方法测试</h2>
    <el-scrollbar class="wrap">
        <div class="item">
            <h4 @click="apply">Reflect.apply(target, thisArg, args)</h4>
            <p>用于绑定this对象后执行给定函数</p>
            <p>1、target:必须是Function,否则TypeError报错。2、thisArg:函数内的this引用对象。3、args:函数实参,数组形式接收多个参数。</p>
        </div>

        <div class="item">
            <h4 @click="construct">Reflect.construct(target, args)</h4>
            <p>调用函数或类的构造器,相当于new操作</p>
            <p>1、target:必须是函数或类。2、args:函数实参,数组形式接收多个参数。</p>
        </div>

        <div class="item">
            <h4 @click="get">Reflect.get(target, name, receiver)</h4>
            <p>查找并返回target对象的name属性，如果没有该属性，则返回undefined</p>
            <p>1、target:必须是对象,否则TypeError报错。2、name:属性名。</p>
        </div>

        <div class="item">
            <h4 @click="set">Reflect.set(target, name, value, receiver)</h4>
            <p>设置target对象的name属性等于value</p>
            <p>1、target:必须是对象,否则TypeError报错。2、name:属性名。3、value:属性值。</p>
        </div>

        <div class="item">
            <h4 @click="defineProperty">Reflect.defineProperty(target, name, desc)</h4>
            <p></p>
            <p>1、target:必须是对象,否则TypeError报错。2、name:属性名。3、desc:描述属性的特性的对象。</p>
        </div>

        <div class="item">
            <h4 @click="deleteProperty">Reflect.deleteProperty(target, name)</h4>
            <p>删除对象的属性</p>
            <p>1、target:必须是对象,否则TypeError报错。2、name:属性名。</p>
        </div>

        <div class="item">
            <h4 @click="has">Reflect.has(target, name)</h4>
            <p>对象是否存在属性</p>
            <p>1、target:必须是对象,否则TypeError报错。2、name:属性名。</p>
        </div>

        <div class="item">
            <h4 @click="ownKeys">Reflect.ownKeys(target)</h4>
            <p>返回对象的所有属性,包括symbol属性</p>
            <p>1、target:必须是对象,否则TypeError报错。</p>
        </div>

        <div class="item">
            <h4 @click="isExtensible">Reflect.isExtensible(target)</h4>
            <p>对象是否可扩展</p>
            <p>1、target:必须是对象,否则TypeError报错。</p>
        </div>

        <div class="item">
            <h4 @click="preventExtensions">Reflect.preventExtensions(target)</h4>
            <p>阻止对象扩展,意味着对象不能添加</p>
            <p>1、target:必须是对象,否则TypeError报错。</p>
        </div>

        <div class="item">
            <h4 @click="getOwnPropertyDescriptor">Reflect.getOwnPropertyDescriptor(target, name)</h4>
            <p>得到指定属性的描述对象</p>
            <p>1、target:必须是对象,否则TypeError报错。2、name:属性名。</p>
        </div>

        <div class="item">
            <h4 @click="getPrototypeOf">Reflect.getPrototypeOf(target)</h4>
            <p>用于读取对象的__proto__属性</p>
            <p>1、target:必须是对象,否则TypeError报错。</p>
        </div>

        <div class="item">
            <h4 @click="setPrototypeOf">Reflect.setPrototypeOf(target, prototype)</h4>
            <p>设置目标对象的原型（prototype）</p>
            <p>1、target:必须是对象,否则TypeError报错。2、prototype:原型对象。</p>
        </div>
    </el-scrollbar>
</template>
    
<script setup>
const apply = () => {
    const obj = {
        name: 'Alice',
        greet: function (f, l) {
            console.log(`Hello, ${f} ${l}!`);
            console.log(`Hello, ${this.name}!`);
        }
    };

    // 使用 Reflect.apply 调用 obj 对象的 greet 方法
    Reflect.apply(obj.greet, obj, ['jack', 'ma']); // 输出: Hello, Alice!

    // 尝试错误的使用 Reflect.apply
    Reflect.apply(obj.name, obj, []); // TypeError: obj.name is not a function
}

const construct = () => {
    // function Greeting(name) {
    //     this.name = name;
    // }
    class Greeting {
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
    }

    // new 的写法
    // const instance = new Greeting('张三');

    // Reflect.construct 的写法
    const instance = Reflect.construct(Greeting, ['张三', 18]);
    console.log(instance);
}

const get = () => {
    const obj = {
        name: 'Alice',
        age: 25
    }
    const name = Reflect.get(obj, 'name'); // 获取 obj 对象的 name 属性
    const sex = Reflect.get(obj, 'sex');
    // const name1 = Reflect.get('obj', 'name'); // TypeError: Reflect.get called on non-object

    console.log(name);  //Alice
    console.log(sex);   //undefined
}

const set = () => {
    const obj = {
        name: 'Alice',
        age: 25
    }
    const flag = Reflect.set(obj, 'sex', 'female'); // 设置 obj 对象的 sex 属性
    console.log(flag);
    console.log(obj);
}

const defineProperty = () => {
    const obj = {};
    const res = Reflect.defineProperty(obj, 'prop', {
        // value: 'good', //value,writable不能和get,set同时使用
        // writable: true,
        enumerable: true,
        configurable: true,
        get() {
            return 'good'
        },
        set(value) {
            Reflect.set(obj, 'propValue', value);
        }
    });
    console.log(obj.prop);  // 输出: 'good'
    obj.prop = 1
    console.log(res);  // 输出: true
}

const deleteProperty = () => {
    const myObj = { foo: 'bar' };

    // 旧写法
    // delete myObj.foo;

    // 新写法
    const flag = Reflect.deleteProperty(myObj, 'foo');
    console.log(myObj);
    console.log(flag);
}

const has = () => {
    const myObject = {
        foo: 1,
    };

    // 旧写法
    console.log('foo' in myObject); // true

    // 新写法
    const flag = Reflect.has(myObject, 'foo') // true
    console.log(flag);
}

const ownKeys = () => {
    const myObject = {
        foo: 1,
        bar: 2,
        [Symbol.for('baz')]: 3,
        [Symbol.for('bing')]: 4,
        [Symbol('bang')]: 5
    };

    // 旧写法
    const name = Object.getOwnPropertyNames(myObject)
    console.log(name);  // ['foo', 'bar']

    const symbol = Object.getOwnPropertySymbols(myObject)
    console.log(symbol);  //[Symbol(baz), Symbol(bing)]

    // 新写法
    const all = Reflect.ownKeys(myObject)
    console.log(all);  // ['foo', 'bar', Symbol(baz), Symbol(bing)]
}

const isExtensible = () => {
    const myObject = {};

    // 旧写法
    const flag1 = Object.isExtensible(myObject) // true
    console.log(flag1);

    // 新写法
    const flag2 = Reflect.isExtensible(myObject) // true
    console.log(flag2);

    // 阻止对象扩展
    const flag3 = Reflect.preventExtensions(myObject) // true
    const flag4 = Reflect.isExtensible(myObject) // false
    console.log(flag3, flag4);
}

const preventExtensions = () => {
    const myObject = {
        foo: 1,
    };
    // const flag1 = Reflect.preventExtensions(myObject) // true
    const flag2 = Reflect.set(myObject, 'bar', 2)
    // myObject.baz = 3 // TypeError: Cannot add property baz, object is not extensible
    console.log(flag2); // false
    console.log(myObject); // {foo: 1}
}

const getOwnPropertyDescriptor = () => {
    const myObject = {};
    Object.defineProperty(myObject, 'hidden', {
        value: 'good',//value默认undefined
        // configurable,enumerable,writable默认是false
    });

    // 旧写法
    const desc1 = Object.getOwnPropertyDescriptor(myObject, 'hidden');
    console.log(desc1);

    // 新写法
    const desc2 = Reflect.getOwnPropertyDescriptor(myObject, 'hidden');
    console.log(desc2);
}

const getPrototypeOf = () => {
    function FancyThing() {
        this.name = 1
    }
    const myObj = new FancyThing();

    // 旧写法
    const flag1 = Object.getPrototypeOf(myObj) === FancyThing.prototype;
    console.log(flag1);

    // 新写法
    const flag2 = Reflect.getPrototypeOf(myObj) === FancyThing.prototype;
    console.log(flag2);

    console.log(myObj);
    console.log(Reflect.getPrototypeOf(myObj).__proto__ === Object.prototype); //true
}

const setPrototypeOf = () => {
    const myObj = {};
    const arr = []

    // 旧写法
    Object.setPrototypeOf(myObj, Array.prototype);

    // 新写法
    Reflect.setPrototypeOf(myObj, Array.prototype);

    myObj.length // 0
    myObj.push(1)
    myObj.push(2)
    arr.push(1)
    arr.push(2)
    console.log(myObj);
    console.log(arr);
    console.log(myObj.__proto__ === Array.prototype);

    Reflect.setPrototypeOf(myObj, {
        getName() {
            return 'jack ma'
        }
    });
    console.log(myObj.getName());
}

</script>
    
<style lang="scss" scoped>
div {
    margin: 10px;
}
h2 {
    margin: 10px;
    padding: 0 10px;
}
h4 {
    color: #fff;
    cursor: pointer;
}
.wrap {
    height: calc(100vh - 100px);
}
.item {
    padding: 0 10px;
    border: 1px solid #ccc;
    p:nth-of-type(1) {
        color: #145daa;
        font-weight: 500;
    }
    p:nth-of-type(2) {
        color: rgb(86, 200, 177);
        font-weight: 500;
    }
}
</style>